home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 351-375 / disk_351 / pdc / libsrc.lzh / LibSrc / SysIO / lib.asm < prev    next >
Assembly Source File  |  1990-04-07  |  23KB  |  444 lines

  1.  
  2.                SECTION 1,CODE
  3.  
  4. *****************************************************************************
  5. * How to to long multiplication with a sixteen bit multiply:
  6. * - Handle special cases
  7. *   - Guaranteed < 32 bits (two shorts)
  8. *   - Guaranteed overflow (both > 16 bits)
  9. * - Perform as if with sixteen bit "digits":
  10. *                      u1         l1                    H(X) = High word of X
  11. *                    x u2         l2                     L(X) = Low word of X
  12. *              ---------------------
  13. *              L(l2 * u1) L(l2 * l1)
  14. *              H(l2 * l1)                       (carry the 2^16's place)
  15. *              L(u2 * l1)
  16. *   H(u2 * l1)                                  (carry the 2^32's place)
  17. *   --------------------------------
  18. *   If the third column is greater than zero, or the total of the second column
  19. *   is greater than 2^16, then there is an overflow condition.
  20. *****************************************************************************
  21. *                                                                           *
  22. *       .lmuls  long signed multiply                                        *
  23. *                                                                           *
  24. *       multiplies two long operands on the stack and returns the           *
  25. *       result on the stack, along with the second operand.                 *
  26. *                                                                           *
  27. *****************************************************************************
  28.                XDEF    .lmuls
  29. .lmuls:
  30.                link    A6,#0           ; Link the current frame
  31.                movem.l D0-D4,-(A7)     ; Save the registers
  32.                tst.w   8(A6)           ; Test the high word for zero
  33.                bne     Lmul1           ;       do a full multiply
  34.                tst.w   12(A6)          ; Test the high word for zero
  35.                bne     Lmul1           ;       do a full multiply
  36.                move.w  10(A6),D0       ; Move the first word
  37.                mulu    14(A6),D0       ; Do a half multiply
  38.                move.l  D0,8(A6)        ; Replace the answer on the stack
  39.                movem.l (A7)+,D0-D4     ; Restore the registers
  40.                unlk    A6
  41.                rts                     ; Return answer in D0
  42. Lmul1:
  43.                move.l  #1,D4           ; Load the sign of the answer
  44.                move.l  8(A6),D2        ; Load the first argument into D2
  45.                bge     Lmul2
  46.                neg.l   D2              ; Make first argument positive
  47.                neg.l   D4              ; Adjust the sign of the result
  48. Lmul2:
  49.                move.l  12(A6),D3       ; Load the second argument into D3
  50.                bge     Lmul3
  51.                neg.l   D3              ; Make the second argument positive
  52.                neg.l   D4              ; Adjust the sign of the result
  53. Lmul3:
  54.                clr.l   D0              ; Clear high word of D0
  55.                move.w  D2,D0           ; Move low word of first argument
  56.                mulu    D3,D0           ; Multiply by low word of second arg
  57.                move.w  D2,D1           ; Save low word of first arg
  58.                swap    D2              ; Exchange low and high word of arg #1
  59.                mulu    D3,D2           ; Multiply by low word of arg #2
  60.                swap    D3              ; Exchange low and high word of arg #2
  61.                mulu    D3,D1           ; Multiply high word of #2 by low #1
  62.                add.l   D2,D1           ; Add the partial results
  63.                swap    D1              ; Swap the low and high of partial ans.
  64.                clr.w   D1              ; Clear the unneeded low word
  65.                add.l   D1,D0           ; Add the partial results to get ans.
  66.                tst.l   D4              ; Test if the result should be negative
  67.                bge     Lmul4
  68.                neg.l   D0              ; Change result
  69. Lmul4:
  70.                move.l  D0,8(A6)        ; Replace the answer on the stack
  71.                movem.l (A7)+,D0-D4     ; Restore the registers
  72.                unlk    A6
  73.                rts
  74.  
  75. ******************************************************************************
  76. *                                                                            *
  77. *       .lmulu   long unsigned multiply (LMU)                                *
  78. *                                                                            *
  79. *       multiplies two long operands on the stack and returns the            *
  80. *       result on the stack, along with the second operand.                  *
  81. *                                                                            *
  82. ******************************************************************************
  83.                XDEF    .lmulu
  84. .lmulu:
  85.                link    A6,#0           ; Link the current frame
  86.                movem.l D0-D3,-(A7)     ; Save the registers
  87.                tst.w   8(A6)           ; See if we have overflow or simple case
  88.                beq     LMUTstSecond    ;       
  89.                tst.w   12(A6)          ; Possible overflow
  90.                bne     LMUOverflow     ;       Uhoh; go deal with it
  91. LMUTough:                              ; A mixed bag (tougher case)
  92.                move.l  8(A6),D2        ; Cache u1.l1 in D2
  93.                move.l  12(A6),D3       ; Cache u2.l2 in D3
  94.                clr.l   D0              ; Prepare to collect result in D0
  95.                move.w  D2,D0           ; Multiply l1 (in D2) and l2 (in D3)
  96.                mulu    D3,D0           ; 
  97.                move.w  D2,D1           ; l1 -> D1 and u1 -> D2
  98.                swap    D2              ; 
  99.                mulu    D3,D2           ; (u1 * l2) -> D2
  100.                swap    D3              ; u2 -> D3
  101.                mulu    D3,D1           ; (u2 * l1) -> D1
  102.                add.l   D2,D1           ; Add the partial results
  103.                swap    D1              ; Swap into high word where it belongs
  104.                tst.w   D1              ; Test the low word, H(u2 * l1)
  105.                bne     LMUOverflow
  106.                add.l   D1,D0           ; Add the partial results to get ans.
  107.                bcc     LMUDone
  108. LMUOverflow:
  109.                move.l  #$FFFFFFFF,D0   ; An alternate response should be to
  110.                bra     LMUDone         ; throw up a SIGFPE.
  111. LMUTstSecond:
  112.                tst.w   12(A6)          ; Check for simple case
  113.                bne     LMUTough
  114.                move.w  10(A6),D0       ; Simple case!
  115.                mulu    14(A6),D0       ; Do a half multiply and get outta town
  116. LMUDone:
  117.                move.l  D0,8(A6)        ; Replace the answer on the stack
  118.                movem.l (A7)+,D0-D3     ; Restore the registers
  119.                unlk    A6
  120.                rts                     ; Also return answer in D0
  121.  
  122. ******************************************************************************
  123. *                                                                            *
  124. *       .ldivs   long signed divide                                          *
  125. *                                                                            *
  126. *       divides two long operands on the stack and returns the               *
  127. *       result on the stack, along with the second operand.                  *
  128. *                                                                            *
  129. ******************************************************************************
  130.  
  131.                XDEF    .ldivs
  132. .ldivs:
  133.                link    A6,#0           ; Link the current frame
  134.                movem.l D0,-(A7)        ; Save the registers
  135.  
  136.                tst.w   12(A6)          ; Test the high word of arg #2
  137.                bne.s   Ldiv1           ; If not zero do a full divide
  138.                move.l  8(A6),D0        ; Test the high word of arg #1
  139.                bmi.s   Ldiv1           ; If negative do full divide
  140.                divu    14(A6),D0       ; Perform the division
  141.                bvs.s   Ldiv1           ; If overflow then do full divide
  142.                and.l   #65535,D0       ; Mask the results into 16 bits
  143.  
  144.                move.l  D0,8(A6)        ; Replace the answer on the stack
  145.                movem.l (A7)+,D0        ; Restore the registers
  146.                unlk    A6
  147.                rts                     ; Return to the caller
  148. Ldiv1:
  149.                movem.l D1-D5,-(A7)     ; Save the aux registers
  150.                move.l  #1,D5           ; Set the sign of the result
  151.                move.l  8(A6),D0        ; Load arg #1
  152.                bge.s   Ldiv2           ; If negative, then
  153.                neg.l   D0              ;       adjust the sign of arg #1
  154.                neg.l   D5              ;       and the result
  155. Ldiv2:
  156.                move.l  D0,D3           ; Save arg #1
  157.                move.l  12(A6),D1       ; Load arg #2
  158.                bge.s   Ldiv3           ; If negative, then
  159.                neg.l   D1              ;       adjust the sign of arg #2
  160.                neg.l   D5              ;       and the result
  161. Ldiv3:
  162.                move.l  D1,D4           ; Save arg #2
  163.                cmp.l   #65536,D1       ; If the divisor is bigger than a word
  164.                bge.s   Ldiv4           ;       do the big division algorithm
  165.                clr.w   D0              ; Clear the low word of arg #1
  166.                swap    D0              ; Move high word into low word
  167.                divu    D1,D0           ; Get partial results
  168.                move.w  D0,D2           ; and Save into reg D2
  169.                move.w  D3,D0           ; Move low word of arg #1 into D0
  170.                divu    D1,D0           ; Get more partial results
  171.                swap    D0              ; Exchange low and high words of result
  172.                move.w  D2,D0           ; Move low word of partial into D0
  173.                swap    D0              ; Exchange low and high words
  174.                bra.s   Ldiv6
  175. Ldiv4:
  176.                lsr.l   #1,D0           ; Divide denumerator
  177.                lsr.l   #1,D1           ; and numerator by 2
  178.                cmp.l   #65536,D1       ; If still too big then
  179.                bge.s   Ldiv4           ; repeat
  180.                divu    D1,D0           ; Perform the division
  181.                and.l   #65535,D0       ; Mask the results to 16 bits
  182.                move.l  D0,D2           ; Save the preliminary result
  183.                move.l  D0,-(A7)        ; Test the result by multiplying
  184.                move.l  D4,-(A7)        ;       The quoient by the divisor
  185.                bsr     .lmuls          ;       Call the multiply routine
  186.                move.l  (A7)+,D0        ;       Retrieve the answer
  187.                add.w   #4,A7           ;       Adjust the stack pointer
  188.                cmp.l   D0,D3           ; If our guess is too hight
  189.                bge.s   Ldiv5           ;       Then
  190.                subq.l  #1,D2           ;               adjust our guess down
  191. Ldiv5:
  192.                move.l  D2,D0           ; Move the results into D0
  193. Ldiv6:
  194.                tst.l   D5              ; Test the sign of the result
  195.                bge.s   Ldiv7           ; If negative
  196.                neg.l   D0              ;       then adjust the result
  197. Ldiv7:
  198.                move.l  D0,8(A6)        ; Replace the answer on the stack
  199.                movem.l (A7)+,D1-D5     ; Restore the aux registers
  200.                movem.l (A7)+,D0        ; Restore the registers
  201.                unlk    A6
  202.                rts                     ; Return to the caller
  203.  
  204. ******************************************************************************
  205. *                                                                            *
  206. *       .ldivu   long unsigned divide (LDU)                                  *
  207. *                                                                            *
  208. *       divides two long operands on the stack and returns the               *
  209. *       result on the stack, along with the second operand.                  *
  210. *                                                                            *
  211. ******************************************************************************
  212.  
  213.                XDEF    .ldivu
  214. .ldivu:
  215.                link    A6,#0           ; Link the current frame
  216.                movem.l D0,-(A7)        ; Save the registers
  217.  
  218.                move.l  8(A6),D0        ; Get the dividend
  219.                tst.w   12(A6)          ; Test the high word of divisor
  220.                bne.s   LDULookCloser   ; If not zero, then maybe a full divide
  221.                divu    14(A6),D0       ; Else it could be real easy
  222.                bvs.s   LDU32           ; If overflow then do full 32-bits
  223.                and.l   #65535,D0       ; Mask the results into 16 bits
  224.                move.l  D0,8(A6)        ; Replace the answer on the stack
  225. LDUExit:
  226.                movem.l (A7)+,D0        ; Restore the registers
  227.                unlk    A6
  228.                rts                     ; Return to the caller
  229. LDU32:
  230.                movem.l D1/D2,-(A7)
  231.                move.w  14(A6),D1       ; We'll need the denominator a bit more
  232.                moveq.l #0,D2
  233.                swap    D0
  234.                move.w  D0,D2
  235.                divu    D1,D2
  236.                move.w  D2,8(A6)        ; The MSW of the answer
  237.                swap    D2
  238.                move.w  D2,D0
  239.                swap    D0
  240.                divu    D1,D0
  241.                move.w  D0,10(A6)       ; The LSW of the answer
  242.                movem.l (A7)+,D1/D2
  243.                bra     LDUExit
  244. LDULookCloser:
  245.                movem.l D1-D5,-(A7)     ; Save the aux registers
  246.                move.l  12(A6),D1       ; Load arg #2 (divisor) into D1
  247.                cmp.l   D1,D0           ; Screen other simple cases
  248.                bgt     LDULong
  249.                beq     LDUOne
  250.                move.l  #0,D0
  251.                bra     LDUDone
  252. LDUOne         move.l  #1,D0
  253.                bra     LDUDone
  254. LDULong:
  255.                move.l  D0,D5           ; Save the original numerator
  256.                move.l  D1,D3           ; Save the original denominator
  257. LDULoop:
  258.                lsr.l   #1,D0           ; Divide numerator
  259.                lsr.l   #1,D1           ; and denomenator by 2
  260.                cmp.l   #65536,D1       ; If still too big then
  261.                bge.s   LDULoop         ; repeat
  262.                divu    D1,D0           ; Perform the division
  263.                and.l   #$FFFF,D0       ; Mask out the remainder
  264.                move.l  D0,D2           ; Save the preliminary result
  265. LDUTest:
  266.            move.l  D3,-(A7)        ; Test the result by multiplying
  267.                move.l  D2,-(A7)
  268.                bsr     .lmulu          ;       Call the multiply routine
  269.            
  270.          
  271.                move.l  (A7)+,D0        ;       Retrieve the answer
  272.                addq.w  #4,A7
  273.                cmp.l   D5,D0
  274.                beq.s   LDUGood
  275.                blt.s   LDUChkRem
  276.                subq.l  #1,D2
  277.                bra.s   LDUTest         ; Retry test (is this necessary?)
  278. LDUChkRem:
  279.                move.l  D5,D4
  280.                sub.l   D0,D4
  281.                cmp.l   D3,D4           ; If low by the denominator or more
  282.                ble.s   LDUGood         ;       Then
  283.                addq.l  #1,D2           ;               adjust our guess up
  284.                bra.s   LDUTest
  285. LDUGood:
  286.                move.l  D2,D0           ; Move the results into D0
  287. LDUDone:
  288.                move.l  D0,8(A6)        ; Replace the answer on the stack
  289.                movem.l (A7)+,D1-D5     ; Restore the aux registers
  290.                bra     LDUExit
  291.  
  292. ******************************************************************************
  293. *
  294. *       .lmods  long signed modulus (remainder)
  295. *
  296. *       Compute the remainder of the two long operands on the stack and
  297. *               returns the result on the stack, along with the second operand.
  298. *
  299. ******************************************************************************
  300.  
  301.                         XDEF    .lmods
  302. .lmods:
  303.                link    A6,#0           ; Link the current frame
  304.                movem.l D0-D4,-(A7)     ; Save the registers
  305.  
  306.                tst.w   12(A6)          ; Test the high word of arg #2
  307.                bne.s   Lmod1           ; If non-zero do a full remainder
  308.                move.l  8(A6),D0        ; Test the first argument
  309.                bmi.s   Lmod1           ; If negative then do a full remainder
  310.                divu    14(A6),D0       ; Perform the modulus
  311.                bvs.s   Lmod1           ; If overflow then do a full remainder
  312.                clr.w   D0              ; Clear the quotient part
  313.                swap    D0              ; Swap the remainder into the low word
  314.  
  315.                move.l  D0,8(A6)        ; Replace the answer on the stack
  316.                movem.l (A7)+,D0-D4     ; Restore the registers
  317.                unlk    A6
  318.                rts                     ; Return to the caller
  319. Lmod1:
  320.                move.l  #1,D4           ; Set the sign of the result
  321.                move.l  8(A6),D0        ; Get the first argument
  322.                bge.s   Lmod2           ; If negative, then
  323.                neg.l   D0              ;       adjust the sign of the argument
  324.                neg.l   D4              ;       and of the result
  325. Lmod2:
  326.                move.l  D0,D2           ; Save the first argument
  327.                move.l  12(A6),D1       ; Get the second argument
  328.                bge.s   Lmod3           ; If negative, then
  329.                neg.l   D1              ;       adjust the sign of the argument
  330. Lmod3:
  331.                cmp.l   #65536,D1       ; If the moduli is to large, then
  332.                bge.s   Lmod4           ;       use the complete algorithm
  333.                clr.w   D0              ; Clear the low word of arg #1
  334.                swap    D0              ; Exchange low and high words
  335.                divu    D1,D0           ; Do division to get partial result
  336.                move.w  D2,D0           ; Replace low word of arg #1 with arg #2
  337.                divu    D1,D0           ; Do division to get partial result
  338.                clr.w   D0              ; Clear the low word
  339.                swap    D0              ; Exchange low and high words
  340.                bra.s   Lmod7           ; Exit from this routine
  341. Lmod4:
  342.                move.l  D1,D3           ; Save the second argument
  343. Lmod5:
  344.                lsr.l   #1,D0           ; Divide both the dividend and the
  345.                lsr.l   #1,D1           ; Quotient by 2 until
  346.                cmp.l   #65536,D1       ; They both fit in bounds
  347.                bge.s   Lmod5
  348.                divu    D1,D0           ; Perform the division
  349.                and.l   #65535,D0       ; Mask the results to 16 bits
  350.  
  351.                move.l  D0,-(A7)        ; Multiply the quoient
  352.                move.l  D3,-(A7)        ;       By the divisor
  353.                bsr     .lmuls          ; Do the multiply
  354.                move.l  (A7)+,D0        ; Retreive the results
  355.                add.w   #4,A7           ; And adjust the stack
  356.  
  357.                cmp.l   D0,D2           ; If the product is greater
  358.                bcc.s   Lmod6           ; Than what we started with, then
  359.                sub.l   D3,D0           ;       subract off the divisor
  360. Lmod6:
  361.                sub.l   D2,D0           ; Get the remainder since we subtracted
  362.                neg.l   D0              ; backwords, we will just negate the answer
  363. Lmod7:
  364.                tst.l   D4              ; Check the sign of the result
  365.                bge.s   Lmod8           ; If it should be negative, then
  366.                neg.l   D0              ;       adjust our answer
  367. Lmod8:
  368.                move.l  D0,8(A6)        ; Replace the answer on the stack
  369.                movem.l (A7)+,D0-D4     ; Restore the registers
  370.                unlk    A6
  371.                rts                     ; Return to the caller
  372.  
  373. ******************************************************************************
  374. *
  375. *       .lmodu  long unsigned modulus (LMU)
  376. *
  377. *       Compute the remainder of the two long operands on the stack and
  378. *               returns the result on the stack, along with the second operand.
  379. *
  380. ******************************************************************************
  381.  
  382.                         XDEF    .lmodu
  383. .lmodu:
  384.                link    A6,#0           ; Link the current frame
  385.                movem.l D0-D3,-(A7)     ; Save the registers
  386.  
  387.                move.l  8(A6),D0        ; Get the base
  388.                tst.w   12(A6)          ; Test the HIGH word of the modulus
  389.                bne.s   LMUfull         ; If non-zero do a full remainder
  390.                divu    14(A6),D0       ; Perform the modulus
  391.                bvs.s   LMUfull         ; If overflow then do a full remainder
  392.                clr.w   D0              ; Clear the quotient part
  393.                swap    D0              ; Swap the remainder into the low word
  394.  
  395.                move.l  D0,8(A6)        ; Replace the answer on the stack
  396.                movem.l (A7)+,D0-D3     ; Restore the registers
  397.                unlk    A6
  398.                rts                     ; Return to the caller
  399. LMUfull:
  400.                move.l  12(A6),D3       ; Get the ENTIRE modulus
  401.                move.l  D0,D2           ; Put the base in a safe register
  402.                move.l  D3,-(A7)
  403.                move.l  D0,-(A7)
  404.                bsr     .ldivu          ; Leave result on stack and call ...
  405.                move.l  D3,-(A7)
  406.                bsr     .lmulu
  407.                move.l  (A7)+,D1
  408.                addq.w  #8,A7           ; Restore also from previous funcall
  409.                sub.l   D1,D2           ; Return base - ((base/modulo)*modulo)
  410.                move.l  D2,8(A6)        ; Replace the answer on the stack
  411.                movem.l (A7)+,D0-D3     ; Restore the registers
  412.                unlk    A6
  413.                rts                     ; Return to the caller
  414.  
  415. *
  416. *       .cswitch - execute c switch statement
  417. *
  418. *       the switch table is encoded as follows:
  419. *
  420. *               long    label1,case1
  421. *               long    label2,case2
  422. *               long    label3,case3
  423. *               ... for all cases
  424. *               long    0,defaultcase
  425. *
  426. *       the case variable is passed in D0
  427. *
  428.                XDEF    .cswitch
  429.  
  430. .cswitch:
  431.                move.l  (A7)+,A0        ;get table address
  432. L_sw1:
  433.                move.l  (A0)+,A1        ;get a label
  434.                move.l  A1,D1           ;test it for default
  435.                beq.s   L_sw2           ;jump if default case
  436.                cmp.l   (A0)+,D0        ;see if this case
  437.                bne.s   L_sw1           ;next case if not
  438.                jmp     (A1)            ;jump to case
  439. L_sw2:
  440.                move.l  (A0),A0         ;get default address
  441.                jmp     (A0)            ;jump to default case
  442.  
  443.                END
  444.